/**
 * 登录获取Token
 */
(function () {
  const expires = 3600;   // Token1小时过期
  const lock_minutes = 5;  // 锁定时间5分钟

  return function ({ UID, User, Password, redirect_uri }, headers) {
    const real_ip = (headers['X-Real-IP'] || []).join(',');
    const card_用户 = A.card('B.用户');
    const card_登录审计 = A.card('B.登录审计');
    // 使用用户名和密码登录
    if (User && Password) {
      const { rows } = A.db.execute(card_用户.连接名称, "SELECT ID,MM,TY FROM B_YH WHERE YHM=?", [User]);
      if (rows.length === 0) {
        card_登录审计.save({
          用户名: User,
          来源地址: real_ip,
          是否通过: 0
        }, UID);
        throw Error("用户名不存在");
      }
      if (rows[0].TY === 1) {
        card_登录审计.save({
          用户名: User,
          来源地址: real_ip,
          是否通过: 0
        }, UID);
        throw Error("用户已停用");
      }

      if (rows[0].MM == null) {
        card_登录审计.save({
          用户名: User,
          来源地址: real_ip,
          是否通过: 0
        }, UID);
        throw Error("密码未设置");
      }
      const error_times = A.cache.get('__error_times__.' + User);
      if (error_times >= 5) {
        card_登录审计.save({
          用户名: User,
          来源地址: real_ip,
          是否通过: 0
        }, UID);
        throw Error("用户已锁定");
      }
      if (rows[0].MM.toLowerCase() !== Password.toLowerCase()) {
        card_登录审计.save({
          用户名: User,
          来源地址: real_ip,
          是否通过: 0
        }, UID);
        // 错误次数+1，刷新锁定时间计时
        A.cache.set('__error_times__.' + User, (error_times ?? 0) + 1, lock_minutes * 60);
        throw Error(error_times >= 4 ? `用户已锁定. 请${lock_minutes}分钟后再试` : "密码错误");
      }

      const token = A.jwt.create({
        UID: rows[0].ID,
        IP: real_ip,
      }, expires);

      // 密码验证通过, 重置错误次数
      A.cache.delete('__error_times__.' + User);

      card_登录审计.save({
        用户名: User,
        来源地址: real_ip,
        是否通过: 1
      }, UID);

      return { token, expires, redirect_uri };
    }

    throw Error('登录失败');
  };
})();